static void name##_IO_APIC_irq (unsigned int irq) \
__DO_ACTION(R, ACTION, FINAL)
-DO_ACTION( __mask, 0, |= 0x00010000, io_apic_sync(entry->apic) )
- /* mask = 1 */
-DO_ACTION( __unmask, 0, &= 0xfffeffff, )
- /* mask = 0 */
-DO_ACTION( __mask_and_edge, 0, = (reg & 0xffff7fff) | 0x00010000, )
- /* mask = 1, trigger = 0 */
-DO_ACTION( __unmask_and_level, 0, = (reg & 0xfffeffff) | 0x00008000, )
- /* mask = 0, trigger = 1 */
+DO_ACTION( __mask, 0, |= 0x00010000, io_apic_sync(entry->apic) )
+DO_ACTION( __unmask, 0, &= 0xfffeffff, )
+DO_ACTION( __edge, 0, &= 0xffff7fff, )
+DO_ACTION( __level, 0, |= 0x00008000, )
static void mask_IO_APIC_irq (unsigned int irq)
{
return 0; /* don't check for pending */
}
-static void end_level_ioapic_irq (unsigned int irq)
+static void mask_and_ack_level_ioapic_irq(unsigned int irq)
{
unsigned long v;
int i;
balance_irq(irq);
+ mask_IO_APIC_irq(irq);
+
/*
* It appears there is an erratum which affects at least version 0x11
* of I/O APIC (that's the 82093AA and cores integrated into various
atomic_inc(&irq_mis_count);
#endif
spin_lock(&ioapic_lock);
- __mask_and_edge_IO_APIC_irq(irq);
+ __edge_IO_APIC_irq(irq);
#ifdef APIC_LOCKUP_DEBUG
for (entry = irq_2_pin + irq;;) {
unsigned int reg;
entry = irq_2_pin + entry->next;
}
#endif
- __unmask_and_level_IO_APIC_irq(irq);
+ __level_IO_APIC_irq(irq);
spin_unlock(&ioapic_lock);
}
}
-static void mask_and_ack_level_ioapic_irq (unsigned int irq) { /* nothing */ }
+static void end_level_ioapic_irq(unsigned int irq)
+{
+ unmask_IO_APIC_irq(irq);
+}
static inline void init_IO_APIC_traps(void)
{
#include <xen/interrupt.h>
#include <xen/irq.h>
#include <xen/slab.h>
+#include <xen/event.h>
#include <asm/mpspec.h>
#include <asm/io_apic.h>
#include <asm/msr.h>
unsigned long irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = ~0UL };
#endif
+static void __do_IRQ_guest(int irq);
+
/*
* Special irq handlers.
*/
* waste of time and is not what some drivers would
* prefer.
*/
-int handle_IRQ_event(unsigned int irq, struct pt_regs * regs, struct irqaction * action)
+static int handle_IRQ_event(unsigned int irq,
+ struct pt_regs * regs,
+ struct irqaction * action)
{
int status;
int cpu = smp_processor_id();
spin_lock(&desc->lock);
desc->handler->ack(irq);
+
/*
REPLAY is when Linux resends an IRQ that was dropped earlier
WAITING is used by probe to mark irqs that are being tested
status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING);
status |= IRQ_PENDING; /* we _want_ to handle it */
+ /* We hook off guest-bound IRQs for special handling. */
+ if ( status & IRQ_GUEST )
+ {
+ __do_IRQ_guest(irq);
+ spin_unlock(&desc->lock);
+ return 1;
+ }
+
/*
* If the IRQ is disabled for whatever reason, we cannot use the action we
* have.
* The following block of code has to be executed atomically
*/
spin_lock_irqsave(&desc->lock,flags);
+
+ if ( desc->status & IRQ_GUEST )
+ {
+ spin_unlock_irqrestore(&desc->lock,flags);
+ return -EBUSY;
+ }
+
p = &desc->action;
if ((old = *p) != NULL) {
/* Can't share interrupts unless both agree to */
desc->status &= ~(IRQ_DISABLED | IRQ_AUTODETECT | IRQ_WAITING);
desc->handler->startup(irq);
}
+
spin_unlock_irqrestore(&desc->lock,flags);
return 0;
}
+
+
+
+/*
+ * HANDLING OF GUEST-BOUND PHYSICAL IRQS
+ */
+
+#define IRQ_MAX_GUESTS 7
+typedef struct {
+ unsigned int nr_guests;
+ struct task_struct *guest[IRQ_MAX_GUESTS];
+} irq_guest_action_t;
+
+static void __do_IRQ_guest(int irq)
+{
+ irq_desc_t *desc = &irq_desc[irq];
+ irq_guest_action_t *action = (irq_guest_action_t *)desc->action;
+ struct task_struct *p;
+ int i;
+
+ for ( i = 0; i < action->nr_guests; i++ )
+ {
+ p = action->guest[i];
+ send_guest_pirq(p, irq);
+ }
+}
+
+int pirq_guest_bind(struct task_struct *p, int irq)
+{
+ unsigned long flags;
+ irq_desc_t *desc = &irq_desc[irq];
+ irq_guest_action_t *action;
+ int rc;
+
+ if ( !IS_PRIV(p) )
+ return -EPERM;
+
+ spin_lock_irqsave(&desc->lock, flags);
+
+ if ( !(desc->status & IRQ_GUEST) )
+ {
+ rc = -EBUSY;
+ if ( desc->action != NULL )
+ goto out;
+
+ rc = -ENOMEM;
+ action = kmalloc(sizeof(irq_guest_action_t), GFP_KERNEL);
+ if ( (desc->action = (struct irqaction *)action) == NULL )
+ goto out;
+
+ action->nr_guests = 0;
+
+ desc->depth = 0;
+ desc->status |= IRQ_GUEST;
+ desc->status &= ~(IRQ_DISABLED | IRQ_AUTODETECT | IRQ_WAITING);
+ desc->handler->startup(irq);
+ }
+
+ action = (irq_guest_action_t *)desc->action;
+
+ rc = -EBUSY;
+ if ( action->nr_guests == IRQ_MAX_GUESTS )
+ goto out;
+
+ action->guest[action->nr_guests++] = p;
+
+ out:
+ spin_unlock_irqrestore(&desc->lock, flags);
+ return rc;
+}
+
+int pirq_guest_unbind(struct task_struct *p, int irq)
+{
+ unsigned long flags;
+ irq_desc_t *desc = &irq_desc[irq];
+ irq_guest_action_t *action;
+ int i;
+
+ spin_lock_irqsave(&desc->lock, flags);
+
+ action = (irq_guest_action_t *)desc->action;
+
+ if ( action->nr_guests == 1 )
+ {
+ desc->action = NULL;
+ kfree(action);
+ desc->status |= IRQ_DISABLED;
+ desc->status &= ~IRQ_GUEST;
+ desc->handler->shutdown(irq);
+ }
+ else
+ {
+ i = 0;
+ while ( action->guest[i] != p )
+ i++;
+ memmove(&action->guest[i], &action->guest[i+1], IRQ_MAX_GUESTS-i-1);
+ action->nr_guests--;
+ }
+
+ spin_unlock_irqrestore(&desc->lock, flags);
+ return 0;
+}
#include <xen/errno.h>
#include <xen/sched.h>
#include <xen/event.h>
+#include <xen/irq.h>
#include <hypervisor-ifs/hypervisor-if.h>
#include <hypervisor-ifs/event_channel.h>
{
struct task_struct *p = current;
int pirq = bind->pirq;
- int port;
+ int port, rc;
if ( pirq >= ARRAY_SIZE(p->pirq_to_evtchn) )
return -EINVAL;
spin_lock(&p->event_channel_lock);
- if ( ((port = p->pirq_to_evtchn[pirq]) != 0) ||
- ((port = get_free_port(p)) < 0) )
+ if ( ((rc = port = p->pirq_to_evtchn[pirq]) != 0) ||
+ ((rc = port = get_free_port(p)) < 0) )
goto out;
+ p->pirq_to_evtchn[pirq] = port;
+ if ( (rc = pirq_guest_bind(p, pirq)) != 0 )
+ {
+ p->pirq_to_evtchn[pirq] = 0;
+ goto out;
+ }
+
p->event_channel[port].state = ECS_PIRQ;
p->event_channel[port].u.pirq = pirq;
- p->pirq_to_evtchn[pirq] = port;
-
out:
spin_unlock(&p->event_channel_lock);
- if ( port < 0 )
- return port;
+ if ( rc < 0 )
+ return rc;
bind->port = port;
return 0;
break;
case ECS_PIRQ:
- p1->pirq_to_evtchn[chn1[port1].u.pirq] = 0;
+ if ( (rc = pirq_guest_unbind(p1, chn1[port1].u.pirq)) == 0 )
+ p1->pirq_to_evtchn[chn1[port1].u.pirq] = 0;
break;
case ECS_VIRQ:
/* bit offsets into state */
#define ST_BASE_ADDRESS 0 /* bits 0-5: are for base address access */
#define ST_ROM_ADDRESS 6 /* bit 6: is for rom address access */
-#define ST_IRQ_DELIVERED 7 /* bit 7: waiting for end irq call */
-typedef struct _phys_dev_st
-{
+typedef struct _phys_dev_st {
int flags; /* flags for access etc */
struct pci_dev *dev; /* the device */
struct list_head node; /* link to the list */
struct task_struct *owner; /* 'owner of this device' */
int state; /* state for various checks */
-
- hw_irq_controller *new_handler; /* saved old handler */
- hw_irq_controller *orig_handler; /* saved old handler */
-
} phys_dev_t;
-#define MAX_IRQS 32
-/* an array of device descriptors index by IRQ number */
-static phys_dev_t *irqs[MAX_IRQS];
-
/*
*
* General functions
return 0;
}
-static void phys_dev_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
-{
- phys_dev_t *pdev;
-
- if ( (pdev = (phys_dev_t *)dev_id) == NULL )
- {
- printk("spurious interrupt, no proper device id, %d\n", irq);
- return;
- }
-
- /* XXX KAF: introduced race here? */
- set_bit(ST_IRQ_DELIVERED, &pdev->state);
- send_guest_pirq(pdev->owner, irq);
-}
-
-/* this is called instead of the PICs original end handler.
- * the real end handler is only called once the guest signalled the handling
- * of the event. */
-static void end_virt_irq (unsigned int i)
-{
- /* nothing */
-}
-
-/*
- * a guest request an IRQ from a device to be routed to it
- * - shared interrupts are not allowed for now
- * - we change the hw_irq handler to something else
- */
-static long pirq_request(int irq)
-{
- int err;
- phys_dev_t *pdev = NULL, *t;
- hw_irq_controller *new, *orig;
- struct list_head *tmp;
-
- printk("request irq %d\n", irq);
-
- /* find pdev */
-
- list_for_each(tmp, ¤t->pcidev_list)
- {
- t = list_entry(tmp, phys_dev_t, node);
- if ( t->dev->irq == irq )
- {
- pdev = t;
- break;
- }
- }
-
- if ( pdev == NULL )
- {
- printk("no device matching IRQ %d\n", irq);
- return -EINVAL;
- }
-
- if ( irq >= MAX_IRQS )
- {
- printk("requested IRQ to big %d\n", irq);
- return -EINVAL;
- }
-
- if ( irqs[irq] != NULL )
- {
- printk ("irq already in use %d\n", irq);
- return -EPERM;
- }
-
- /* allocate a hw_irq controller and copy the original */
- if ( !(new = kmalloc(sizeof(hw_irq_controller), GFP_KERNEL)) )
- {
- printf("error allocating new irq controller\n");
- return -ENOMEM;
- }
- orig = irq_desc[irq].handler;
- new->typename = orig->typename;
- new->startup = orig->startup;
- new->shutdown = orig->shutdown;
- new->enable = orig->enable;
- new->disable = orig->disable;
- new->ack = orig->ack;
- new->end = orig->end;
- new->set_affinity = orig->set_affinity;
-
- /* swap the end routine */
- new->end = end_virt_irq;
-
- /* change the irq controllers */
- pdev->orig_handler = orig;
- pdev->new_handler = new;
- irq_desc[irq].handler = new;
- irqs[irq] = pdev;
-
- printk ("setup handler %d\n", irq);
-
- /* request the IRQ. this is not shared and we use a slow handler! */
- err = request_irq(irq, phys_dev_interrupt, SA_INTERRUPT,
- "foo", (void *)pdev);
- if ( err )
- {
- printk("error requesting irq\n");
- /* restore original */
- irq_desc[irq].handler = pdev->orig_handler;
- /* free memory */
- kfree(new);
- return err;
- }
-
- printk ("done\n");
-
- return 0;
-}
-
-long pirq_free(int irq)
-{
- phys_dev_t *pdev;
-
- if ( irq >= MAX_IRQS )
- {
- printk("requested IRQ to big %d\n", irq);
- return -EINVAL;
- }
-
- if ( irqs[irq] == NULL )
- {
- printk ("irq not used %d\n", irq);
- return -EINVAL;
- }
-
- pdev = irqs[irq];
-
- /* shutdown IRQ */
- free_irq(irq, (void *)pdev);
-
- /* restore irq controller */
- irq_desc[irq].handler = pdev->orig_handler;
-
- /* clean up */
- pdev->orig_handler = NULL;
- irqs[irq] = NULL;
- kfree(pdev->new_handler);
- pdev->new_handler = NULL;
-
- printk("freed irq %d", irq);
- return 0;
-}
static long pci_unmask_irq(void)
{
-#if 0
- clear_bit(ST_IRQ_DELIVERED, &pdev->state);
- pdev->orig_handler->end(irq);
-#endif
return 0;
}
static char serial_rx_ring[SERIAL_RX_SIZE];
static unsigned int serial_rx_cons, serial_rx_prod;
-/* CTRL-a switches input direction between Xen and DOM0. */
-#define CTRL_A 0x01
+/* CTRL-g switches input direction between Xen and DOM0. */
+#define CTRL_G 0x07
static int xen_rx = 1; /* FALSE => serial input passed to domain 0. */
static void switch_serial_input(void)
static char *input_str[2] = { "DOM0", "Xen" };
xen_rx = !xen_rx;
printk("*** Serial input -> %s "
- "(type 'CTRL-a' three times to switch input to %s).\n",
+ "(type 'CTRL-g' three times to switch input to %s).\n",
input_str[xen_rx], input_str[!xen_rx]);
}
static void serial_rx(unsigned char c, struct pt_regs *regs)
{
- static int ctrl_a_count = 0;
+ static int ctrl_g_count = 0;
- if ( c == CTRL_A )
+ if ( c == CTRL_G )
{
- /* We eat CTRL-a in groups of three to switch console input. */
- if ( ++ctrl_a_count == 3 )
+ /* We eat CTRL-g in groups of three to switch console input. */
+ if ( ++ctrl_g_count == 3 )
{
switch_serial_input();
- ctrl_a_count = 0;
+ ctrl_g_count = 0;
}
}
else
{
- /* Flush any pending CTRL-a's. They weren't for us. */
- for ( ; ctrl_a_count != 0; ctrl_a_count-- )
- __serial_rx(CTRL_A, regs);
+ /* Flush any pending CTRL-b's. They weren't for us. */
+ for ( ; ctrl_g_count != 0; ctrl_g_count-- )
+ __serial_rx(CTRL_G, regs);
/* Finally process the just-received character. */
__serial_rx(c, regs);
}
#include <xen/irq.h>
-#ifdef CONFIG_SMP /*more of this file should probably be ifdefed SMP */
+#if defined(CONFIG_X86_IO_APIC)
static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i) {
- if (IO_APIC_IRQ(i))
- send_IPI_self(IO_APIC_VECTOR(i));
+ if (IO_APIC_IRQ(i))
+ send_IPI_self(IO_APIC_VECTOR(i));
}
#else
static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i) {}
#include <xen/irq.h>
-#ifdef CONFIG_SMP /*more of this file should probably be ifdefed SMP */
+#if defined(CONFIG_X86_IO_APIC)
static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i) {
- if (IO_APIC_IRQ(i))
- send_IPI_self(IO_APIC_VECTOR(i));
+ if (IO_APIC_IRQ(i))
+ send_IPI_self(IO_APIC_VECTOR(i));
}
#else
static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i) {}
#define IRQ_NONE
#define IRQ_HANDLED
#define IRQ_RETVAL(x)
-
+
struct irqaction {
void (*handler)(int, void *, struct pt_regs *);
unsigned long flags;
struct irqaction *next;
};
-
enum {
TIMER_BH = 0,
SCSI_BH
-#ifndef __irq_h
-#define __irq_h
+#ifndef __XEN_IRQ_H__
+#define __XEN_IRQ_H__
#include <xen/config.h>
#include <xen/spinlock.h>
#define IRQ_REPLAY 8 /* IRQ has been replayed but not acked yet */
#define IRQ_AUTODETECT 16 /* IRQ is being autodetected */
#define IRQ_WAITING 32 /* IRQ not yet seen - for autodetection */
-#define IRQ_LEVEL 64 /* IRQ level triggered */
-#define IRQ_MASKED 128 /* IRQ masked - shouldn't be seen again */
-#define IRQ_PER_CPU 256 /* IRQ is per CPU */
+#define IRQ_GUEST 64 /* IRQ is handled by guest OS(es) */
/*
* Interrupt controller descriptor. This is all we need
* to describe about the low-level hardware.
*/
struct hw_interrupt_type {
- const char * typename;
- unsigned int (*startup)(unsigned int irq);
- void (*shutdown)(unsigned int irq);
- void (*enable)(unsigned int irq);
- void (*disable)(unsigned int irq);
- void (*ack)(unsigned int irq);
- void (*end)(unsigned int irq);
- void (*set_affinity)(unsigned int irq, unsigned long mask);
+ const char *typename;
+ unsigned int (*startup)(unsigned int irq);
+ void (*shutdown)(unsigned int irq);
+ void (*enable)(unsigned int irq);
+ void (*disable)(unsigned int irq);
+ void (*ack)(unsigned int irq);
+ void (*end)(unsigned int irq);
+ void (*set_affinity)(unsigned int irq, unsigned long mask);
};
-typedef struct hw_interrupt_type hw_irq_controller;
+typedef struct hw_interrupt_type hw_irq_controller;
#include <asm/irq.h>
* Pad this out to 32 bytes for cache and indexing reasons.
*/
typedef struct {
- unsigned int status; /* IRQ status */
- hw_irq_controller *handler;
- struct irqaction *action; /* IRQ action list */
- unsigned int depth; /* nested irq disables */
- spinlock_t lock;
+ unsigned int status; /* IRQ status */
+ hw_irq_controller *handler;
+ struct irqaction *action; /* IRQ action list */
+ unsigned int depth; /* nested irq disables */
+ spinlock_t lock;
} ____cacheline_aligned irq_desc_t;
-extern irq_desc_t irq_desc [NR_IRQS];
+extern irq_desc_t irq_desc[NR_IRQS];
-extern int handle_IRQ_event(unsigned int, struct pt_regs *, struct irqaction *);
-extern int setup_irq(unsigned int , struct irqaction * );
+extern int setup_irq(unsigned int, struct irqaction *);
-extern hw_irq_controller no_irq_type; /* needed in every arch ? */
+extern hw_irq_controller no_irq_type;
extern void no_action(int cpl, void *dev_id, struct pt_regs *regs);
-#endif /* __asm_h */
+struct task_struct;
+extern int pirq_guest_bind(struct task_struct *p, int irq);
+extern int pirq_guest_unbind(struct task_struct *p, int irq);
+
+#endif /* __XEN_IRQ_H__ */